/*
 * Created by: vadikv
 * Created: Friday, March 07, 2008
 */

using System;
using System.Collections.Generic;
using OneDayModel.Interfaces;
using OneDayModel.Model;

namespace OneDayModel.Model
{
    public class User : IUser
    {
        private const string attrAccountStatus = "AccountStatus";
        private readonly List<IRole> assignedRoles = new List<IRole>();
        private readonly IRepository repository;
        private readonly IConfirmationServices confirmationServices;
        private readonly List<KeyValuePair<string, string >> changes = new List<KeyValuePair<string, string>>();
        private readonly Dictionary<string, string> attributes = new Dictionary<string, string>();
        private readonly Dictionary<string, IAlbum> albums = new Dictionary<string, IAlbum>();

        public User(IRepository repository, IConfirmationServices confirmationServices)
        {
            this.repository = repository;
            this.confirmationServices = confirmationServices;
            attributes.Add(attrAccountStatus, AccountStatus.notExist.ToString());
        }

        public User(IRepository repository, IConfirmationServices confirmationServices, string password, string alias, string email, string accountStatus):
            this(repository, confirmationServices)
        {
            attributes.Add("Password", password);
            attributes.Add("Alias", alias);
            attributes.Add("eMail", email);
            this[attrAccountStatus] = accountStatus;
        }

 
        public void AssignRole(IRole role)
        {
            if (!assignedRoles.Contains(role))
                assignedRoles.Add(role);
        }

        public void SetAttributes(IAttributeRecord[] attributes)
        {
            foreach (AttributeRecord attribute in attributes)
            {
                this.attributes.Add(attribute.RoleAttribute.Name, attribute.Value);
            }
        }

        public void Create()
        {
            AccountStatus status = AccountStatus.existAndWaitingForConfirmation;
            this[attrAccountStatus] = status.ToString();
            repository.CreateUser(this["Alias"], this["eMail"], this["Password"], assignedRoles, attributes, status);
            confirmationServices.SendConfirmation(this["Alias"], this["eMail"]);
        }                                         

        public void SetUserAccountStatus(AccountStatus accountStatus)
        {
            string status = accountStatus.ToString();
            if (this[attrAccountStatus] != status)
            {
                this[attrAccountStatus] = status;
                changes.Add(new KeyValuePair<string, string>(attrAccountStatus, status));
            }
        }


        public void CommitChanges()
        {
            repository.UpdateUser(this["Alias"], changes);
        }

        public void AddAlbum(IAlbum album)
        {
            albums.Add(album.Name, album);
        }

        public IAlbum GetAlbum(string albumName)
        {
            if (albums.ContainsKey(albumName))
                return albums[albumName];
            else
            {
                IAlbum album = repository.GetAlbumForUser(this["Alias"], albumName);
                if (album != null)
                    AddAlbum(album);

                return album;
            }
        }

        public string this[string attributeName]
        {
            get
            {
                string value;
                if (attributes.TryGetValue(attributeName, out value))
                    return value;

                throw new AttributeNotFoundException(attributeName);
            }
            set
            {
                if (attributes.ContainsKey(attributeName))
                {
                    attributes[attributeName] = value;
                    return;
                }

                throw new AttributeNotFoundException(attributeName);
            }
        }
    }

    public class AttributeNotFoundException : ApplicationException
    {
        public AttributeNotFoundException(string attributeName)
            : base("Attribute \"" + attributeName + "\" not defined for user")
        {

        }
    }
}